﻿// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
#include "pch.h"
#include "WeathrMain.h"
#include "Common\DirectXHelper.h"

#include <DirectXColors.h>          // For named colors
#include "Common\DirectXHelper.h"   // For ThrowIfFailed

using namespace Weathr;
using namespace Windows::Foundation;
using namespace Windows::System::Threading;
using namespace Concurrency;

// Loads and initializes application assets when the application is loaded.
WeathrMain::WeathrMain(const std::shared_ptr<DeviceResources>& deviceResources) :
    m_deviceResources(deviceResources), m_pointerLocationX(0.0f)
{
    // Register to be notified if the Device is lost or recreated
    m_deviceResources->RegisterDeviceNotify(this);

    m_sceneRenderer = std::make_unique<SceneRenderer>(m_deviceResources);

    // TODO: use event token (when suspended)
    // Register the rendering event, called every time XAML renders the screen.
    // The value may be already valid if activated from secondary tile while already running.
    //if (m_eventToken.Value == 0)
    //{
    //   m_eventToken = Windows::UI::Xaml::Media::CompositionTarget::Rendering::add(ref new EventHandler<Platform::Object^>(m_blah, &Blah::OnRendering));
    //}
}

WeathrMain::~WeathrMain()
{
    // Deregister device notification
    m_deviceResources->RegisterDeviceNotify(nullptr);
}

// Updates application state when the window size changes (e.g. device orientation change)
void WeathrMain::CreateWindowSizeDependentResources()
{
    // TODO: Replace this with the size-dependent initialization of your app's content.
    m_sceneRenderer->CreateWindowSizeDependentResources();
}

void WeathrMain::StartRenderLoop()
{
    //// If the animation render loop is already running then do not start another thread.
    //if (m_renderLoopWorker != nullptr && m_renderLoopWorker->Status == AsyncStatus::Started)
    //{
    //    return;
    //}

    //// Create a task that will be run on a background thread.
    //auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction ^ action)
    //{
    //    // Calculate the updated frame and render once per vertical blanking interval.
    //    while (action->Status == AsyncStatus::Started)
    //    {
    //        critical_section::scoped_lock lock(m_criticalSection);
    //        Update();
    //        if (Render())
    //        {
    //            m_deviceResources->Present();
    //        }
    //    }
    //});

    //// Run task on a dedicated high priority background thread.
    //m_renderLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced);
}

void WeathrMain::StopRenderLoop()
{
    //m_renderLoopWorker->Cancel();
}

// Updates the application state once per frame.
void WeathrMain::Update()
{
    m_timer.Tick([this]()
    {
        m_sceneRenderer->Update(m_timer);
    });
}

// Renders the current frame according to the current application state.
// Returns true if the frame was rendered and is ready to be displayed.
bool WeathrMain::Render()
{
    // Don't try to render anything before the first Update.
    if (m_timer.GetFrameCount() == 0)
    {
        return false;
    }

    auto context = m_deviceResources->GetD3DDeviceContext();

    // Reset the viewport to target the whole screen.
    auto viewport = m_deviceResources->GetScreenViewport();
    context->RSSetViewports(1, &viewport);

    // Reset render targets to the screen.
    ID3D11RenderTargetView *const targets[1] = { m_deviceResources->GetBackBufferRenderTargetView() };
    context->OMSetRenderTargets(1, targets, m_deviceResources->GetDepthStencilView());

    // Clear the back buffer and depth stencil view.
    context->ClearRenderTargetView(m_deviceResources->GetBackBufferRenderTargetView(), DirectX::Colors::Black);
    context->ClearDepthStencilView(m_deviceResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    // Render the scene objects.
    m_sceneRenderer->Render();

    return true;
}

// Notifies renderers that device resources need to be released.
void WeathrMain::OnDeviceLost()
{
    m_sceneRenderer->ReleaseDeviceDependentResources();
}

// Notifies renderers that device resources may now be recreated.
void WeathrMain::OnDeviceRestored()
{
    m_sceneRenderer->CreateDeviceDependentResources();
    CreateWindowSizeDependentResources();
}
